import React, { ReactElement, useReducer, useEffect, Dispatch, useImperativeHandle, forwardRef, Ref, HTMLAttributes } from 'react'
import { Table, TablePaginationConfig } from 'antd'
import qs from 'query-string'
import { ColumnsType } from 'antd/lib/table'
import { reducer, initialState } from './reducer'
import { CaseSchema } from '../schema/caseSchema'

// 改变表单
function tableChange (p: TablePaginationConfig, sorter: { [k: string]: any }, state: typeof initialState, params: {[k: string]: any}, setParams: (v: {[k: string]: any}) => void): void {
  const o: { [k: string]: any } = {
    ...params,
    page: p.pageSize !== state.pageSize ? 1 : p.current,
    limit: p.pageSize
  }
  if (typeof sorter.order === 'string') {
    o.order_field = sorter.field
    o.order = sorter.order === 'ascend' ? 'asc' : 'desc'
  } else {
    o.order_field = undefined
    o.order = undefined
  }
  setParams(qs.parse(qs.stringify(o)))
}

// 处理选择结果
function dealSelected (isCheckbox: boolean, list: Array<{id: React.Key, [k: string]: any}>, prevKeys: React.Key[], selectedRowKeys: React.Key[], setSelectedRowKeys: (v: React.Key[]) => void, selectedRows: any[], setSelectedRows: (v: any[]) => void): void {
  if (isCheckbox) {
    const ids: React.Key[] = list.map(li => li.id)
    const otherIds = prevKeys.filter(id => !ids.includes(id))
    const otherRows = selectedRows.filter(({ id }: {id: React.Key}) => !ids.includes(id))
    const currentRows = list.filter(({ id }) => selectedRowKeys.includes(id))
    setSelectedRowKeys([...otherIds, ...selectedRowKeys])
    setSelectedRows([...otherRows, ...currentRows])
  } else {
    setSelectedRowKeys(selectedRowKeys)
    setSelectedRows(list.filter(({ id }) => selectedRowKeys.includes(id)))
  }
}

interface Props {
  params: {[k: string]: any}
  loading?: boolean
  columns?: ColumnsType<any>
  dataSource?: any[]
  total?: number
  totalUnit?: string
  selectable?: boolean
  selectType?: 'checkbox' | 'radio'
  selectedRowKeys?: React.Key[]
  selectedRows?: any[]
  rowKey?: string
  pagenation?: TablePaginationConfig | false
  onChange: (o: { [k: string]: any}) => void
  setSelectedRowKeys?: (v: React.Key[]) => void
  setSelectedRows?: (v: any[]) => void
  setParams: (v: {[k: string]: any}) => void
}

export interface TableRef {
  refreshData: () => void
}

function Main ({ params, dataSource = [], columns = [], loading = false, total = 0, totalUnit = '条', selectable = false, rowKey, onChange, selectType = 'checkbox', selectedRowKeys = [], setSelectedRowKeys = () => {}, selectedRows = [], setSelectedRows = () => {}, pagenation, setParams }: Props, ref: Ref<TableRef>): ReactElement {
  const o = params
  const onRow = function (record: CaseSchema): HTMLAttributes<HTMLElement> {
    return {
      onClick: function (e): void {
        if (!selectable) {
          return undefined
        }
        const keys = [...selectedRowKeys]
        const index = selectedRowKeys.indexOf(record.id)
        if (selectType === 'checkbox') {
          if (index === -1) {
            keys.push(record.id)
          } else {
            keys.splice(index, 1)
          }
          setSelectedRowKeys(keys)
        } else {
          setSelectedRowKeys([record.id])
        }
        const rows = [...selectedRows]
        const rowKeys = rows.map(li => li.id)
        const rIndex = rowKeys.indexOf(record.id)
        if (selectType === 'checkbox') {
          if (rIndex === -1) {
            rows.push(record)
          } else {
            rows.splice(rIndex, 1)
          }
          setSelectedRows(rows)
        } else {
          setSelectedRows([record])
        }
      }
    }
  }
  const [state, dispatch] = useReducer(reducer, initialState, (d) => {
    const data = { ...d }
    data.showTotal = (total: number) => `合计 ${total} ${totalUnit}`
    if (typeof o.page === 'string' && /^\d+$/.test(o.page)) {
      data.current = parseInt(o.page)
    }
    if (typeof o.limit === 'string' && /^\d+$/.test(o.limit)) {
      data.pageSize = parseInt(o.limit)
    }
    return data
  })
  function init (o: {[k: string]: any}): void {
    if (typeof o.page === 'string' && /^\d+$/.test(o.page)) {
      o.page = parseInt(o.page)
    } else {
      o.page = 1
    }
    if (typeof o.limit === 'string' && /^\d+$/.test(o.limit)) {
      o.limit = parseInt(o.limit)
    } else {
      o.limit = 10
    }
    onChange(o)
  }
  useEffect(() => {
    const o = params
    if (typeof o.page === 'string' && /^\d+$/.test(o.page)) {
      dispatch({ type: 'current', data: parseInt(o.page) })
    } else {
      dispatch({ type: 'current', data: 1 })
    }
    if (typeof o.limit === 'string' && /^\d+$/.test(o.limit)) {
      dispatch({ type: 'pageSize', data: parseInt(o.limit) })
    } else {
      dispatch({ type: 'pageSize', data: 10 })
    }
    init(params)
  }, [params])
  useImperativeHandle(ref, () => ({
    refreshData: () => {
      init(params)
    }
  }))
  return (
    <div>
      <Table rowKey={typeof rowKey === 'string' ? rowKey : 'id'} loading={loading} columns={columns} dataSource={dataSource} pagination={ pagenation === undefined ? { ...state, total } : pagenation } onChange={(pagination, filters, sorter) => tableChange(pagination, sorter, state, params, setParams)} rowSelection={selectable ? { type: selectType, selectedRowKeys, onChange: (keys: React.Key[], rows: any[]) => { dealSelected(selectType === 'checkbox', dataSource, selectedRowKeys, keys, setSelectedRowKeys, selectedRows, setSelectedRows) } } : undefined} onRow={onRow} />
    </div>
  )
}

export default forwardRef(Main)
